/*
 * TCSS 422 Web Spider Project
 * Group Money: Al McKenzie, Michael Pitts, Taylor Zielske
 */
package model;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;

/**
 * This class sets up a buffer for a single url and allows it to be parsed one line at
 * a time.  It can be either a normal url or a url for a domain's robots.txt file.
 * 
 * @author Michael Pitts
 * @version Oct 22, 2011
 */
public final class URLParser implements  AutoCloseable, Closeable {
	
	/**
	 * Indicates a normal url.
	 */
	public static final int NORMAL_URL = 0;
	
	/**
	 * Indicates a domain's robots.txt url.
	 */
	public static final int DOMAIN_URL = 1;
	
	/**
	 * Indicates the domain's robots.txt could not be found.
	 */
	public static final int OPEN_DOMAIN = 2;
	
	/**
	 * Indicates the domain could not be buffered.
	 */
	public static final int NO_DOMAIN = 3;
	
	/**
	 * Buffered input to the url's web page.
	 */
	private final BufferedReader my_reader;
	
	/**
	 * The actual url.
	 */
	private final URL my_url;
	
	/**
	 * The type of this ParseURL.
	 */
	private final int my_type;
	
	/**
	 * Creates a new URL Parser with the given url and type.
	 * @param the_url is the url to be loaded and parsed.
	 * @param the_type is the type of the url, either normal or robots.txt.
	 * @throws IOException is the buffered reader can't be set up.
	 * @see BufferedReader
	 */
	public URLParser(final URL the_url, final int the_type) throws IOException {
		this(the_url, the_type, 
				new BufferedReader(new InputStreamReader(the_url.openStream())));
	}
	
	/**
	 * Creates a new URLParser, with the buffer specified in the input.
	 * @param the_url is the url to be loaded and parsed.
	 * @param the_type is the type of the url, either normal or robots.txt.
	 * @param the_reader is the BufferedReader that will be used to provide input.
	 */
	public URLParser(final URL the_url, final int the_type, 
			final BufferedReader the_reader) {
		my_url = the_url;
		my_type = the_type;
		my_reader = the_reader;
	}
	
	/**
	 * Returns true if the buffered reader is ready to be read.
	 * @return true if data can be read, false otherwise.
	 * @throws IOException if the BufferdReader throws an I/O error.
	 * @see BufferedReader#ready()
	 */
	public boolean ready() throws IOException {
		return my_reader.ready();
	}
	
	/**
	 * Reads a single line of text from the buffer.
	 * @return a string with a single line of data from the buffered reader.
	 * @throws IOException if the buffer throws an I/O exception while reading.
	 * @see BufferedReader#readLine()
	 */
	public String readLine() throws IOException {
		return my_reader.readLine();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override public void close() throws IOException {
		my_reader.close();
	}

	/**
	 * Returns the type of url this is, either a normal url or a robots.txt.
	 * @return an integer indicating the type of url this is.
	 */
	public int getType() {
		return my_type;
	}
	
	/**
	 * Gets the underlying url for this Parser.
	 * @return the url being used for this parser.
	 * @see URL
	 */
	public URL getURL() {
		return my_url;
	}
	
	/**
	 * Gets a fake buffered reader which does nothing.  This is for URLParsers that 
	 * can't or won't be reading data.
	 * @return a new BufferedReader that is always ready but never gives output.
	 */
	public static BufferedReader getFakeReader() {
		return new BufferedReader(getFakeReaderInternal()) {
			@Override public String readLine() {
				return null;
			}
			
			@Override public boolean ready() {
				return true;
			}
		};
	}
	
	/**
	 * Gets a fake Reader so the fake BufferedReader does not error.
	 * @return a fake Reader.
	 */
	private static Reader getFakeReaderInternal() {
		return new Reader() {

			@Override public void close() throws IOException {
				// don't do anything
			}

			@Override public int read(char[] the_arg0, int the_arg1, int the_arg2)
					throws IOException {
				// don't do anything
				return 0;
			}
			
		};
	}
}
